package teamproject.graphEditor.graphGenerators;

import java.util.ArrayList;

import teamproject.graphEditor.Controller;
import teamproject.graphEditor.Node;
import teamproject.graphEditor.NodeFactory;
import teamproject.graphEditor.PDEEdge;
import teamproject.graphEditor.PDEEdgeFactory;
import teamproject.graphEditor.SortCollectionsToArray;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;

/**
 * Generates a block network represented by a directed graph. A blocknetwork is
 * specified by its dimension, e.g. a 4x4 block network.
 */
public class BlockNetworkGenerator implements GraphGenerator {

	private Controller control;
	private int dimension;
	private DirectedGraph<Node, PDEEdge> g;

	/**
	 * Creates an instance of this object with a standard dimension of 4.
	 * 
	 * @param control
	 *            Controller which contains the node and edge factories
	 */
	public BlockNetworkGenerator(Controller control) {
		this(control, 4);
	}

	/**
	 * Creates an instance of this object.
	 * 
	 * @param control
	 *            Controller which contains the node and edge factories
	 * @param dimension
	 *            the dimension of a block network
	 */
	public BlockNetworkGenerator(Controller control, int dimension) {
		this.control = control;
		this.dimension = dimension;
	}

	private void creatEdges(DirectedGraph<Node, PDEEdge> g) {
		// Node[] nodes = g.getVertices().toArray(new Node[0]);
		PDEEdgeFactory factory = control.getEdgeFactory();

		SortCollectionsToArray sca = new SortCollectionsToArray();
		ArrayList<Node> blockNodes = sca.sortNodes(g.getVertices());

		// QuickSort quicksort = new QuickSort(nodes);
		// quicksort.sortNodes();

		// create horizontal lines
		for (int i = 0; i < blockNodes.size(); i++) {
			if (i + 1 <= blockNodes.size()) {
				if ((i + 1) % (dimension + 2) != 0)
					g.addEdge(factory.create(), blockNodes.get(i),
							blockNodes.get(i + 1));
			}
		}

		// create vertical lines
		for (int i = dimension + 2; i < blockNodes.size(); i++) {
			if (i % (dimension + 2) != 0
					&& i % (dimension + 2) != (dimension + 1)) {
				g.addEdge(factory.create(), blockNodes.get(i),
						blockNodes.get(i - (dimension + 2)));
			}
		}

		// create diagonal lines
		for (int i = dimension + 2; i < blockNodes.size(); i++) {
			if (i % (dimension + 2) != 0
					&& i % (dimension + 2) != (dimension + 1)
					&& i % (dimension + 2) != dimension) {
				g.addEdge(factory.create(), blockNodes.get(i),
						blockNodes.get(i - (dimension + 1)));
			}
		}
	}

	private void createNodes(DirectedGraph<Node, PDEEdge> g) {
		NodeFactory factory = control.getNodeFactory();

		for (int y = 0; y < dimension; y++) {
			for (int x = 0; x < dimension; x++) {
				g.addVertex(factory.create());
			}
		}

		for (int i = 0; i < dimension * 2; i++) {
			g.addVertex(factory.create());
		}
	}

	@Override
	public DirectedGraph<Node, PDEEdge> generateGraph() {
		g = new DirectedSparseGraph<Node, PDEEdge>();
		g = (DirectedGraph<Node, PDEEdge>) control.initNewGraph(g);

		createNodes(g);
		creatEdges(g);

		return g;
	}
}
